package com.gzzyy.unionchain.communicate

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.util.Log
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.gzzyy.unionchain.LiveEvent
import com.gzzyy.unionchain.communicate.webrtc.WebRtcClient
import com.gzzyy.unionchain.communicate.webrtc.bean.MessageBean
import com.gzzyy.unionchain.communicate.websocket.WsClient
import com.gzzyy.unionchain.data.ObjectBox
import com.gzzyy.unionchain.data.SaveDataService
import com.gzzyy.unionchain.data.bean.Block_
import com.gzzyy.unionchain.data.bean.TransactionRecord_
import com.jeremyliao.liveeventbus.LiveEventBus
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.java_websocket.handshake.ServerHandshake
import java.net.URI

class CommunicateService : Service(), WsClient.ClientListener {

    companion object {
        const val TAG = "CommunicateService"
        const val webSocketUri = "ws://47.114.58.183:9502"
        const val heartBeatFrame = "{\"action\":\"heart_beat\"}"
        var queryHeight = 0
        val handler = Handler()
    }

    private val heartbeatRun = object : Runnable {
        override fun run() {
            Log.e("test", "hearBeatFrame = $heartBeatFrame")
            wsClient.send(heartBeatFrame)
            handler.postDelayed(this, 1000 * 60)
        }
    }

    private fun sendWebSocketMsg(msg: String) {
        if (!(wsClient.isClosed || wsClient.isClosing)) {
            wsClient.send(msg)
        }
    }

    private lateinit var wsClient: WsClient
    private lateinit var webRtcClient: WebRtcClient
    override fun onCreate() {
        super.onCreate()
        wsClient = WsClient(URI(webSocketUri))
        wsClient.clientListener = this@CommunicateService
        wsClient.connect()
        webRtcClient = WebRtcClient()
        LiveEventBus.get(LiveEvent.DataChannelSendMsg, Pair::class.java)
            .observeForever {
                webRtcClient.sendMsg(it.first as String, it.second as String)
            }
        LiveEventBus.get(LiveEvent.DataChannelReceiveMsg, MessageBean::class.java).observeForever {
            //处理其他手机端发出的消息
            Log.i("test", "DataChannelReceiveMsg " + it.msg)
            val pair = Pair(SaveDataService.SaveSingle, it.msg)
            LiveEventBus.get(LiveEvent.SaveData).post(pair)
        }

        LiveEventBus.get(LiveEvent.CommitTransfer, JSONObject::class.java).observeForever {

            val pair = Pair(SaveDataService.CacheSingle, it.toJSONString())
            LiveEventBus.get(LiveEvent.SaveData).post(pair)

            sendWebSocketMessage(it.toJSONString())
            Log.i("test", "MessageToServer " + it.toJSONString())
        }
        LiveEventBus.get(LiveEvent.MessageToServer, JSONObject::class.java).observeForever {
            Log.i("test", "MessageToServer " + it.toJSONString())
            sendWebSocketMessage(it.toJSONString())
        }
        LiveEventBus.get(LiveEvent.MessageToOther, JSONObject::class.java).observeForever {
            Log.i("test", "MessageToOther " + it.toJSONString())
            webRtcClient.sendToAll(it.toJSONString())
        }
        LiveEventBus.get(LiveEvent.RequestTransferList, Pair::class.java).observeForever {
            requestTransferList(it.first as Int, it.second as Int)
        }
    }

    private val localBinder = LocalBinder()
    override fun onBind(intent: Intent): IBinder {
        return localBinder
    }

    inner class LocalBinder : Binder() {
        fun getService(): CommunicateService {
            return this@CommunicateService
        }
    }

    override fun onWebSocketOpen(handshakedata: ServerHandshake?) {
        Log.i("test", "onWebSocketOpen")
        handler.post(heartbeatRun)
        GlobalScope.launch {
            requestTransferList()
            requestBlockList()
        }
    }

    override fun onWebSocketClose(code: Int, reason: String?, remote: Boolean) {
        Log.i("test", "onWebSocketClose")
        try {
            wsClient.connect()
        } catch (e: java.lang.Exception) {

        }
    }

    override fun onWebSocketMessage(message: String?) {
        //处理来自服务端的消息
        Log.i("test", "onWebSocketMessage ${message}")
        val jsonObj = JSON.parseObject(message)
        val errorCode = jsonObj.getIntValue("error_code")
        if (errorCode == 0) {
            val dataObj = jsonObj.getJSONObject("data")
            when (dataObj.getString("action")) {
                Action.Transfer.value -> {
                    val hash = dataObj.getString("hash")
                    val pair = Pair(SaveDataService.SaveSingleByHash, hash)
                    LiveEventBus.get(LiveEvent.SaveData).post(pair)
                    LiveEventBus.get(LiveEvent.TransferResponse).post(Any())
                }
                Action.GetTransfer.value -> {
                    val pair = Pair(SaveDataService.SaveList, dataObj.toJSONString())
                    LiveEventBus.get(LiveEvent.SaveData).post(pair)
                }
                Action.SyncBlock.value -> {
                    val dataArray = dataObj.getJSONArray("data")
                    if (!dataArray.isNullOrEmpty()) {
                        val pair = Pair(SaveDataService.SaveSingleBlock, dataArray.toJSONString())
                        LiveEventBus.get(LiveEvent.SaveData).post(pair)
                    }
                }
                Action.GetBlock.value -> {
                    val blockListStr = dataObj.getJSONArray("list")?.toJSONString()
                    if (!blockListStr.isNullOrEmpty()) {
                        val pair = Pair(SaveDataService.SaveBlockList, blockListStr)
                        LiveEventBus.get(LiveEvent.SaveData).post(pair)
                    }
                }
            }
        }
    }

    override fun onWebSocketError(ex: Exception?) {
        Log.i("test", "onWebSocketError ${ex.toString()}")
    }


    private fun sendWebSocketMessage(msg: String) {
        if (!(wsClient.isClosing or wsClient.isClosed)) {
            wsClient.send(msg)
        }
    }

    private fun requestTransferList() {
        val jsonObj = JSONObject()
        jsonObj["action"] = Action.GetTransfer.value
        jsonObj["height"] = findHeight()
        Log.e("test", "requestTransferList ${jsonObj.toJSONString()}")
        wsClient.send(jsonObj.toJSONString())
    }

    private fun requestBlockList() {
        val jsonObj = JSONObject()
        jsonObj["action"] = Action.GetBlock.value
        jsonObj["height"] = findBlockHeight()
        Log.e("test", "requestBlockList ${jsonObj.toJSONString()}")
        wsClient.send(jsonObj.toJSONString())
    }

    private fun requestTransferList(page: Int, page_size: Int) {
        val jsonObj = JSONObject()
        jsonObj["action"] = Action.GetTransfer.value
        jsonObj["height"] = queryHeight
        jsonObj["page"] = page
        jsonObj["page_size"] = page_size
        wsClient.send(jsonObj.toJSONString())
    }

    private fun findHeight(): Int {
        var height = 0
        val recordBox = ObjectBox.getRecordBox()
        val queryBuilder = recordBox.query()
        val transferBean = queryBuilder.orderDesc(TransactionRecord_.height).build().findFirst()
        if (transferBean != null) {
            height = transferBean.height + 1
        }
        queryHeight = height
        return height
    }

    private fun findBlockHeight(): Int {
        var height = 0
        val blockBox = ObjectBox.getBlockBox()
        val queryBuilder = blockBox.query().orderDesc(Block_.height).build()
        val block = queryBuilder.findFirst()
        if (block != null) {
            height = block.height + 1
        }
        return height
    }
}
